home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / bmutil.c < prev    next >
C/C++ Source or Header  |  1991-04-28  |  25KB  |  1,046 lines

  1. /*
  2.  *    Simple mail user interface for KA9Q IP/TCP package.
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *    Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
  8.  *    Permission granted for non-commercial copying and use, provided
  9.  *    this notice is retained.
  10.  *
  11.  *    Ported to NOS at 900120 by Anders Klemets SM0RGV.
  12.  */
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <time.h>
  17. #include "global.h"
  18. #include "ftpserv.h"
  19. #include "smtp.h"
  20. #include "proc.h"
  21. #include "usock.h"
  22. #include "socket.h"
  23. #include "telnet.h"
  24. #include "timer.h"
  25. #include "session.h"
  26. #include "files.h"
  27.  
  28. #define        SETVBUF
  29. #if    defined(UNIX) || defined(MICROSOFT)
  30. #include    <sys/types.h>
  31. #endif
  32. /*
  33. #if    defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
  34. #include    <sys/stat.h>
  35. #endif
  36. #ifdef AZTEC
  37. #include <stat.h>
  38. #endif
  39. */
  40. #include <fcntl.h>
  41. #include "bm.h"
  42. #include "mailbox.h"
  43.  
  44. #ifdef SETVBUF
  45. #define        MYBUF    1024
  46. #endif
  47.  
  48. extern long ftell();
  49. static char Badmsg[] = "Invalid Message number %d\n";
  50. static char Nomail[] = "No messages\n";
  51. static char Noaccess[] = "Unable to access %s\n";
  52. static int readnotes __ARGS((struct mbx *m,FILE *ifile,int update));
  53. static long isnewmail __ARGS((struct mbx *m));
  54. static int initnotes __ARGS((struct mbx *m));
  55. static int lockit __ARGS((struct mbx *m));
  56. static long fsize __ARGS((char *name));
  57. static void mfclose __ARGS((struct mbx *m));
  58. static int tkeywait __ARGS((char *prompt,int flush));
  59.  
  60. static int
  61. initnotes(m)
  62. struct mbx *m;
  63. {
  64.     FILE    *tmpfile();
  65.     FILE    *ifile;
  66.     register struct    let *cmsg;
  67.     char buf[256];
  68.     int     i, ret;
  69.  
  70.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  71.     if ((ifile = fopen(buf,READ_TEXT)) == NULLFILE)
  72.         return 0;
  73.     fseek(ifile,0L,2);     /* go to end of file */
  74.     m->mboxsize = ftell(ifile);
  75.     rewind(ifile);
  76.     if(!stricmp(m->area,m->name)) /* our private mail area */
  77.         m->mysize = m->mboxsize;
  78.     if ((m->mfile = tmpfile()) == NULLFILE) {
  79.         (void) fclose(ifile);
  80.         return -1;
  81.     }
  82. #ifdef    SETVBUF
  83.     if (m->stdinbuf == NULLCHAR)
  84.         m->stdinbuf = mallocw(MYBUF);
  85.     setvbuf(ifile, m->stdinbuf, _IOFBF, MYBUF);
  86.     if (m->stdoutbuf == NULLCHAR)
  87.         m->stdoutbuf = mallocw(MYBUF);
  88.     setvbuf(m->mfile, m->stdoutbuf, _IOFBF, MYBUF);
  89. #endif
  90.     m->nmsgs = 0;
  91.     m->current = 0;
  92.     m->change = 0;
  93.     m->newmsgs = 0;
  94.     m->anyread = 0;
  95.     /* Allocate space for reading messages */
  96.     free((char *)m->mbox);
  97.     m->mbox = (struct let *)callocw(Maxlet+1,sizeof(struct let));
  98.     ret = readnotes(m,ifile,0);
  99.     (void) fclose(ifile);
  100. #ifdef SETVBUF
  101.     free(m->stdinbuf);
  102.     m->stdinbuf = NULLCHAR;
  103. #endif
  104.     if (ret != 0)
  105.         return -1;
  106.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)  
  107.         if ((cmsg->status & BM_READ) == 0) {
  108.             m->newmsgs++;
  109.             if (m->current == 0)
  110.                 m->current = i;
  111.         }
  112.     /* start at one if no new messages */
  113.     if (m->current == 0)
  114.         m->current++;
  115.  
  116.     return 0;
  117. }
  118.  
  119. /* readnotes assumes that ifile is pointing to the first
  120.  * message that needs to be read.  For initial reads of a
  121.  * notesfile, this will be the beginning of the file.  For
  122.  * rereads when new mail arrives, it will be the first new
  123.  * message.
  124.  */
  125. static int
  126. readnotes(m,ifile,update)
  127. struct mbx *m;
  128. FILE *ifile ;
  129. int update;    /* true if this is not the initial read of the notesfile */
  130. {
  131.     char     tstring[LINELEN];
  132.     long    cpos;
  133.     register struct    let *cmsg;
  134.     register char *line;
  135.  
  136.     cmsg = (struct let *)NULL;
  137.     line = tstring;
  138.     while(fgets(line,LINELEN,ifile) != NULLCHAR) {
  139.         /* scan for begining of a message */
  140.         if(strncmp(line,"From ",5) == 0) {
  141.             pwait(NULL);
  142.             cpos = ftell(m->mfile);
  143.             fputs(line,m->mfile);
  144.             if (m->nmsgs == Maxlet) {
  145.                 tprintf("Mail box full: > %d messages\n",Maxlet);
  146.                 mfclose(m);
  147.                 return -1;
  148.             }
  149.             m->nmsgs++;
  150.             cmsg = &m->mbox[m->nmsgs];
  151.             cmsg->start = cpos;
  152.             if(!update)
  153.                 cmsg->status = 0;
  154.             cmsg->size = strlen(line);
  155.             while (fgets(line,LINELEN,ifile) != NULLCHAR) {
  156.                 if (*line == '\n') { /* done header part */
  157.                     cmsg->size++;
  158.                     putc(*line, m->mfile);
  159.                     break;
  160.                 }
  161.                 if (htype(line) == STATUS) {
  162.                     if (line[8] == 'R') 
  163.                         cmsg->status |= BM_READ;
  164.                     continue;
  165.                 }
  166.                 cmsg->size += strlen(line);
  167.                 if (fputs(line,m->mfile) == EOF) {
  168.                     tprintf("tmp file: %s",sys_errlist[errno]);
  169.                     mfclose(m);
  170.                     return -1;
  171.                 }
  172.  
  173.             }
  174.         } else if (cmsg) {
  175.             cmsg->size += strlen(line);
  176.             fputs(line,m->mfile);
  177.         }
  178.     }
  179.     return 0;
  180. }
  181.  
  182. /* list headers of a notesfile a message */
  183. int
  184. dolistnotes(argc,argv,p)
  185. int argc;
  186. char *argv[];
  187. void *p;
  188. {
  189.     struct mbx *m;
  190.     register struct    let *cmsg;
  191.     register char    *cp, *s;
  192.     char    smtp_date[SLINELEN], smtp_from[SLINELEN];
  193.     char    smtp_subject[SLINELEN], tstring[LINELEN], type;
  194.     int    start, stop;
  195.     long    size;
  196.     char    *area;
  197.  
  198.     m = (struct mbx *) p;
  199.     if (m->mfile == NULLFILE) {
  200.         tprintf(Nomail);
  201.         return 0;
  202.     }
  203.  
  204.     area = strdup(m->area);
  205.     while((cp = strchr(area,'/')) != NULLCHAR)
  206.         *cp = '.';
  207.     tprintf("Mail area: %s  %d message%s -  %d new\n\n",area,m->nmsgs,
  208.         m->nmsgs == 1 ? " " : "s ", m->newmsgs);
  209.     free(area);
  210.  
  211.     stop = m->nmsgs;
  212.     if(m->stype == 'L') {        /* LL (List Latest) command */
  213.          if(argc > 1)
  214.           start = stop - atoi(argv[1]) + 1;
  215.          else
  216.           start = stop;
  217.     }
  218.     else {
  219.          if(argc > 1)
  220.           start = atoi(argv[1]);
  221.          else
  222.           start = 1;
  223.          if(argc > 2)
  224.           stop = atoi(argv[2]);
  225.     }
  226.     if(stop > m->nmsgs)
  227.         stop = m->nmsgs;
  228.     if(start < 1 || start > stop) {
  229.         tprintf("Invalid range.\n");
  230.         return 0;
  231.     }
  232.     for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
  233.         *smtp_date = '\0';
  234.         *smtp_from = '\0';
  235.         *smtp_subject = '\0';
  236.         type = ' ';
  237.         fseek(m->mfile,cmsg->start,0);
  238.         size = cmsg->size;
  239.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  240.                != NULLCHAR) {
  241.             if (*tstring == '\n')    /* end of header */
  242.                 break;
  243.             size -= strlen(tstring);
  244.             rip(tstring);
  245.             /* handle continuation later */
  246.             if (*tstring == ' '|| *tstring == '\t')
  247.                 continue;
  248.             switch(htype(tstring)) {
  249.             case FROM:
  250.                 cp = getaddress(tstring,0);
  251.                 sprintf(smtp_from,"%.30s",
  252.                     cp != NULLCHAR ? cp : "");
  253.                 break;
  254.             case SUBJECT:
  255.                 sprintf(smtp_subject,"%.34s",&tstring[9]);
  256.                 break;
  257.             case DATE:
  258.                 if ((cp = strchr(tstring,',')) == NULLCHAR)
  259.                     cp = &tstring[6];
  260.                 else
  261.                     cp++;
  262.                 /* skip spaces */
  263.                 while (*cp == ' ') cp++;
  264.                 if(strlen(cp) < 17)
  265.                     break;     /* not a valid length */
  266.                 s = smtp_date;
  267.                 /* copy day */
  268.                 if (atoi(cp) < 10 && *cp != '0') {
  269.                     *s++ = ' ';
  270.                 } else
  271.                     *s++ = *cp++;
  272.                 *s++ = *cp++;
  273.  
  274.                 *s++ = ' ';
  275.                 *s = '\0';
  276.                 while (*cp == ' ')
  277.                     cp++;
  278.                 strncat(s,cp,3);    /* copy month */
  279.                 cp += 3;
  280.                 while (*cp == ' ')
  281.                     cp++;
  282.                 /* skip year */
  283.                 while (isdigit(*cp))
  284.                     cp++;
  285.                 /* copy time */
  286.                 strncat(s,cp,6); /* space hour : min */
  287.                 break;
  288.             case BBSTYPE:
  289.                 type = tstring[16];
  290.                 break;
  291.             case NOHEADER:
  292.                 break;
  293.             }
  294.         }
  295.         if((type == m->stype && m->stype != ' ') || m->stype == ' '
  296.            || m->stype == 'L')
  297.              tprintf("%c%c%c%3d %-27.27s %-12.12s %5ld %.25s\n",
  298.                  (start == m->current ? '>' : ' '),
  299.                  (cmsg->status & BM_DELETE ? 'D' : ' '),
  300.                  (cmsg->status & BM_READ ? 'Y' : 'N'),
  301.                  start, smtp_from, smtp_date,
  302.                  cmsg->size, smtp_subject);
  303.     }
  304.     return 0;
  305. }
  306.  
  307. /*  save msg on stream - if noheader set don't output the header */
  308. int
  309. msgtofile(m,msg,tfile,noheader)
  310. struct mbx *m;
  311. int msg;
  312. FILE *tfile;   /* already open for write */
  313. int noheader;
  314. {
  315.     char    tstring[LINELEN];
  316.     long     size;
  317.  
  318.     if (m->mfile == NULLFILE) {
  319.         tprintf(Nomail);
  320.         return -1;
  321.     }
  322.     fseek(m->mfile,m->mbox[msg].start,0);
  323.     size = m->mbox[msg].size;
  324.  
  325.     if (noheader) {
  326.         /* skip header */
  327.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  328.                != NULLCHAR) {
  329.             size -= strlen(tstring);
  330.             if (*tstring == '\n')
  331.                 break;
  332.         }
  333.     }
  334.     while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  335.            != NULLCHAR) {
  336.         size -= strlen(tstring);
  337.         fputs(tstring,tfile);
  338.         if (ferror(tfile)) {
  339.             tprintf("Error writing mail file\n");
  340.             return -1;
  341.         }
  342.     }
  343.     return 0;
  344. }
  345.  
  346. /*  dodelmsg - delete message in current notesfile */
  347. int
  348. dodelmsg(argc,argv,p)
  349. int argc;
  350. char *argv[];
  351. void *p;
  352. {
  353.     struct mbx *m;
  354.     int msg,i;
  355.     m = (struct mbx *) p;
  356.     if (m->mfile == NULLFILE) {
  357.         tprintf(Nomail);
  358.         return 0;
  359.     }
  360.     for(i = 1; i < argc; ++i) {
  361.         msg = atoi(argv[i]);
  362.         if(msg < 0 || msg > m->nmsgs) {
  363.             tprintf(Badmsg,msg);
  364.             continue;
  365.         }
  366.         /* Check if we have permission to delete others mail */
  367.         if(!(m->privs & FTP_WRITE) && stricmp(m->area,m->name)) {
  368.             tprintf(Noperm);
  369.             return 0;
  370.         }
  371.         m->mbox[msg].status |= BM_DELETE;
  372.         tprintf("Msg %d Killed.\n", msg);
  373.         m->change = 1;
  374.     }
  375.     return 0;
  376. }
  377. /* close the temp file while coping mail back to the mailbox */
  378. int
  379. closenotes(m)
  380. struct mbx *m;
  381. {
  382.     register struct    let *cmsg;
  383.     register char *line;
  384.     char tstring[LINELEN], buf[256];
  385.     long size;
  386.     int i, nostatus = 0, nodelete;
  387.     FILE    *nfile;
  388.  
  389.     if (m->mfile == NULLFILE)
  390.         return 0;
  391.  
  392.     if(!m->change) {        /* no changes were made */
  393.         mfclose(m);
  394.         m->mboxsize = 0;
  395.         return 0;
  396.     }
  397.     /* If this area is a public message area, then we will not add a
  398.      * Status line to indicate that the message has been read.
  399.      */
  400.     nostatus = isarea(m->area);
  401.  
  402.     /* Don't delete messages from public message areas unless you are
  403.      * a BBS.
  404.      */
  405.     if(nostatus)
  406.         nodelete = !(m->privs & SYSOP_CMD);
  407.     else
  408.         nodelete = 0;
  409.  
  410.     /* See if any messages have been forwarded, otherwise just close
  411.      * the file and return since there is nothing to write back.
  412.      */
  413.     if(nostatus && nodelete) {
  414.         for(i=1; i <= m->nmsgs; ++i)
  415.             if(m->mbox[i].status & BM_FORWARDED)
  416.                 break;
  417.         if(i > m->nmsgs) {
  418.             mfclose(m);
  419.             m->mboxsize = 0;
  420.             return 0;
  421.         }
  422.     }
  423.     line = tstring;
  424.     scanmail(m);
  425.     if(lockit(m))
  426.         return -1;
  427.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  428.     if ((nfile = fopen(buf,WRITE_TEXT)) == NULLFILE) {
  429.         tprintf(Noaccess,buf);
  430.         mfclose(m);
  431.         m->mboxsize = 0;
  432.         rmlock(Mailspool,m->area);
  433.         return -1;
  434.     }
  435.     /* copy tmp file back to notes file */
  436.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++) {
  437.         fseek(m->mfile,cmsg->start,0);
  438.         size = cmsg->size;
  439.         /* It is not possible to delete messages if nodelete is set */
  440.         if ((cmsg->status & BM_DELETE) && !nodelete)
  441.             continue;
  442.         /* copy the header */
  443.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  444.             size -= strlen(line);
  445.             if (*line == '\n') {
  446.                 if (cmsg->status & BM_FORWARDED)
  447.                     fprintf(nfile,"%s%s\n",Hdrs[XFORWARD],
  448.                         m->name);
  449.                 if ((cmsg->status & BM_READ) != 0 && !nostatus)
  450.                     fprintf(nfile,"%sR\n",Hdrs[STATUS]);
  451.                 fprintf(nfile,"\n");
  452.                 break;
  453.             }
  454.             fputs(line,nfile);
  455.             /* pwait(NULL);  can cause problems if exiting NOS */
  456.         }
  457.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  458.             fputs(line,nfile);
  459.             size -= strlen(line);
  460.             /* pwait(NULL);   dont want no damaged files */
  461.             if (ferror(nfile)) {
  462.                 tprintf("Error writing mail file\n");
  463.                 (void) fclose(nfile);
  464.                 mfclose(m);
  465.                 m->mboxsize = 0;
  466.                 rmlock(Mailspool,m->area);
  467.                 return -1;
  468.             }
  469.         }
  470.     }
  471.     m->nmsgs = 0;
  472.     if (!stricmp(m->name,m->area))
  473.         m->mysize = ftell(nfile); /* Update the size of our mailbox */
  474.     /* remove a zero length file */
  475.     if (ftell(nfile) == 0L)
  476.         (void) unlink(buf);
  477.     (void) fclose(nfile);
  478.     mfclose(m);
  479.     m->mboxsize = 0;
  480.     rmlock(Mailspool,m->area);
  481.     pwait(NULL);
  482.     return 0;
  483. }
  484.  
  485. /* Returns 1 if name is a public message Area, 0 otherwise */
  486. int
  487. isarea(name)
  488. char *name;
  489. {
  490.     char buf[LINELEN], *cp;
  491.     FILE *fp;
  492.     if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
  493.         return 0;
  494.     while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
  495.         /* The first word on each line is all that matters */
  496.         if((cp = strchr(buf,' ')) == NULLCHAR)
  497.             if((cp = strchr(buf,'\t')) == NULLCHAR)
  498.                 continue;
  499.         *cp = '\0';
  500.         if((cp = strchr(buf,'\t')) != NULLCHAR)
  501.             *cp = '\0';
  502.         if(stricmp(name,buf) == 0) {    /* found it */
  503.             fclose(fp);
  504.             return 1;
  505.         }
  506.     }
  507.     fclose(fp);
  508.     return 0;
  509. }
  510.  
  511. static int
  512. lockit(m)
  513. struct mbx *m;
  514. {
  515.     int c, cnt = 0;
  516.  
  517.     while(mlock(Mailspool,m->area)) {
  518.         pause(1000L/MSPTICK);    /* Wait one second */
  519.         if(++cnt == 10) {
  520.             cnt = 0;
  521.             c = tkeywait("Mail file is busy, Abort or Retry ? ",1);
  522.             if (c == 'A' || c == 'a' || c == EOF) {
  523.                 mfclose(m);
  524.                 return 1;
  525.             }
  526.         }
  527.     }
  528.     return 0;
  529. }
  530.  
  531. /* read the next message or the current one if new */
  532. int
  533. doreadnext(argc,argv,p)
  534. int argc;
  535. char *argv[];
  536. void *p;
  537. {
  538.     struct mbx *m;
  539.     char buf[10], *newargv[2];
  540.     m = (struct mbx *) p;
  541.     if (m->mfile == NULLFILE)
  542.         return 0;
  543.     if ((m->mbox[m->current].status & BM_READ) != 0) {
  544.         if (m->current == 1 && m->anyread == 0)
  545.             ;
  546.         else if (m->current < m->nmsgs) {
  547.             m->current++;
  548.         } else {
  549.             tprintf("Last message\n");
  550.             return 0;
  551.         }
  552.     }
  553.     sprintf(buf,"%d",m->current);
  554.     newargv[0] = "read";
  555.     newargv[1] = buf;
  556.     m->anyread = 1;
  557.     return doreadmsg(2,newargv,p);
  558. }
  559.  
  560. /*  display message on the crt given msg number */
  561. int
  562. doreadmsg(argc,argv,p)
  563. int argc;
  564. char *argv[];
  565. void *p;
  566. {
  567.     struct mbx *m;
  568.     register int c, col, lin;
  569.     char    buf[MAXCOL+2], *cp, *cp2;
  570.     int    msg, cnt, i, usemore, verbose, mbxheader, pathcol;
  571.     int    header, lastheader;
  572.     long     size;
  573.  
  574.     m = (struct mbx *) p;
  575.     if (m->mfile == NULLFILE) {
  576.         tprintf(Nomail);
  577.         return 0;
  578.     }
  579.     if(m->type == TELNET || m->type == TIP)
  580.         usemore = 1;    /* Display More prompt */
  581.     else
  582.         usemore = 0;
  583.     lin = MAXLIN-1;
  584.     for(i = 1; i < argc; ++i) {
  585.         msg = atoi(argv[i]);
  586.         if( msg < 1 || msg > m->nmsgs) {
  587.             tprintf(Badmsg,msg);
  588.             return 0;
  589.         }
  590.         fseek(m->mfile,m->mbox[msg].start,0);
  591.         size = m->mbox[msg].size;
  592.         m->current = msg;
  593.         header = NOHEADER;
  594.         mbxheader = 0;
  595.         if(*argv[0] == 'v')
  596.             verbose = 1;    /* display all header lines */
  597.         else
  598.             verbose = 0;
  599.  
  600.         tprintf("Message #%d %s\n", msg,
  601.             m->mbox[msg].status & BM_DELETE ? "[Deleted]" : "");
  602.         if ((m->mbox[msg].status & BM_READ) == 0) {
  603.             m->mbox[msg].status |= BM_READ;
  604.             m->change = 1;
  605.             m->newmsgs--;
  606.         }
  607.         --lin;
  608.         col = 0;
  609.         while (!feof(m->mfile) && size > 0) {
  610.             for (col = 0;  col < MAXCOL;) {
  611.                 c = getc(m->mfile);
  612.                 size--;
  613.                 if (feof(m->mfile) || size == 0) /* end this line */
  614.                     break;
  615.                 if (c == '\t') {
  616.                     cnt = col + 8 - (col & 7);
  617.                     if (cnt >= MAXCOL) /* end this line */
  618.                         break;
  619.                     while (col < cnt)
  620.                         buf[col++] = ' ';
  621.                 } else {
  622.                     if (c == '\n')
  623.                         break;
  624.                     buf[col++] = c;
  625.                 }
  626.             }
  627.             if(col < MAXCOL)
  628.                 buf[col++] = '\n';
  629.             buf[col] = '\0';
  630.             if(mbxheader > 0) {
  631.                  /* Digest R: lines and display as a Path: line */
  632.                  if(strncmp(buf,"R:",2) != 0 ||
  633.                 (cp = strchr(buf,'@')) == NULLCHAR) {
  634.                   tputc('\n');
  635.                   mbxheader = -1; /* don't get here again */
  636.                   verbose = 1;
  637.                  }
  638.                  else {
  639.                   if(*(++cp) == ':')
  640.                        ++cp;
  641.                   for(cp2 = cp; isalnum(*cp2); ++cp2)  ;
  642.                   *cp2 = '\0';
  643.                   if(mbxheader++ == 1) {
  644.                        tputs("Path: ");
  645.                        pathcol = 5;
  646.                        --lin;
  647.                   }
  648.                   else {
  649.                        tputc('!');
  650.                        if(++pathcol + strlen(cp) > MAXCOL-3){
  651.                         tputs("\n      ");
  652.                         pathcol = 5;
  653.                         --lin;
  654.                        }
  655.                   }
  656.                   tputs(cp);
  657.                   pathcol += strlen(cp);
  658.                   ++lin;    /* to allow for not printing it later */
  659.                  }
  660.             }
  661.             if(col == 1 && !verbose && !mbxheader)
  662.                  /* last header line reached */
  663.                  mbxheader = 1;
  664.             if(verbose)
  665.                 tputs(buf);
  666.             if(!verbose && !mbxheader){
  667.                 lastheader = header;
  668.                 if(!isspace(*buf))
  669.                     header = htype(buf);
  670.                 else
  671.                     header = lastheader;
  672.                 switch(header) {
  673.                 case TO:
  674.                 case CC:
  675.                 case FROM:
  676.                 case DATE:
  677.                 case SUBJECT:
  678.                 case APPARTO:
  679.                 case ORGANIZATION:
  680.                     tputs(buf);
  681.                     break;
  682.                 default:
  683.                     ++lin;
  684.                 }
  685.             }
  686.             col = 0;
  687.             if(usemore && --lin == 0){
  688.                 c = tkeywait("--More--",0);
  689.                 lin = MAXLIN-1;
  690.                 if(c == -1 || c == 'q' || c == 'Q')
  691.                     break;
  692.                 if(c == '\n' || c == '\r')
  693.                     lin = 1;
  694.             }
  695.         }
  696.     }
  697.     return 0;
  698. }
  699.  
  700. /* Set up m->to when replying to a message. The subject is returned in
  701.  * m->line.
  702.  */
  703. int
  704. mbx_reply(argc,argv,m,cclist,rhdr)
  705. int argc;
  706. char *argv[];
  707. struct mbx *m;
  708. struct list **cclist;    /* Pointer to buffer for pointers to cc recipients */
  709. char **rhdr;        /* Pointer to buffer for extra reply headers */
  710. {
  711.     char subject[MBXLINE], *msgid = NULLCHAR, *date = NULLCHAR;
  712.     char *cp;
  713.     int msg, lastheader, header = NOHEADER;
  714.     long size;
  715.  
  716.     /* Free anything that might be allocated
  717.      * since the last call to mbx_to() or mbx_reply()
  718.      */
  719.     free(m->to);
  720.     m->to = NULLCHAR;
  721.     free(m->tofrom);
  722.     m->tofrom = NULLCHAR;
  723.     free(m->tomsgid);
  724.     m->tomsgid = NULLCHAR;
  725.     free(m->origto);
  726.     m->origto = NULLCHAR;
  727.     subject[0] = '\0';
  728.  
  729.     if(argc == 1)
  730.          msg = m->current;
  731.     else
  732.          msg = atoi(argv[1]);
  733.     if (m->mfile == NULLFILE) {
  734.          if(m->sid & MBX_SID)
  735.           tputs("NO - ");
  736.         tputs(Nomail);
  737.         return 0;
  738.     }
  739.     if(msg < 1 || msg > m->nmsgs) {
  740.          if(m->sid & MBX_SID)
  741.           tputs("NO - ");
  742.          tputs(Badmsg);
  743.          return -1;
  744.     }
  745.     fseek(m->mfile,m->mbox[msg].start,0);
  746.     size = m->mbox[msg].size;
  747.     m->current = msg;
  748.     while(size > 0 && fgets(m->line,MBXLINE-1,m->mfile) != NULLCHAR) {
  749.          size -= strlen(m->line);
  750.          if(m->line[0] == '\n')    /* end of header */
  751.           break;
  752.          rip(m->line);
  753.          lastheader = header;
  754.          if(!isspace(m->line[0])) {
  755.           header = htype(m->line);
  756.           lastheader = NOHEADER;
  757.          }
  758.          switch(header) {
  759.          case SUBJECT:
  760.           if(strlen(m->line) > 11 && !strnicmp(&m->line[9],"Re:",3))
  761.                strcpy(subject,&m->line[9]);
  762.           else
  763.                sprintf(subject,"Re: %s",&m->line[9]);
  764.           break;
  765.          case FROM:
  766.           if(m->to == NULLCHAR && (cp = getaddress(m->line,0)) !=
  767.              NULLCHAR)
  768.                m->to = strdup(cp);
  769.           break;
  770.          case REPLYTO:
  771.           if((cp = getaddress(m->line,0)) != NULLCHAR) {
  772.                free(m->to);
  773.                m->to = strdup(cp);
  774.           }
  775.           break;
  776.          case MSGID:
  777.           free(msgid);
  778.           msgid = strdup(&m->line[12]);
  779.           break;
  780.          case DATE:
  781.           free(date);
  782.           date = strdup(&m->line[6]);
  783.           break;
  784.          case TO:
  785.          case CC:
  786.          case APPARTO:
  787.           /* Get addresses on To, Cc and Apparently-To lines */
  788.           cp = m->line;
  789.           m->line[strlen(cp)+1] = '\0';    /* add extra null at end */
  790.           for(;;) {
  791.                if((cp = getaddress(cp,lastheader == header ||
  792.                        cp != m->line)) == NULLCHAR)
  793.                 break;
  794.                addlist(cclist,cp,0);
  795.                /* skip to next address, if any */
  796.                cp += strlen(cp) + 1;
  797.           }
  798.           break;
  799.          }
  800.     }
  801.     if(msgid != NULLCHAR || date != NULLCHAR) {
  802.          *rhdr = mallocw(LINELEN);
  803.          sprintf(*rhdr,"In-Reply-To: your message ");
  804.          if(date != NULLCHAR) {
  805.           sprintf(m->line,"of %s.\n",date);
  806.           strcat(*rhdr,m->line);
  807.           if(msgid != NULLCHAR)
  808.                strcat(*rhdr,"             ");
  809.          }
  810.          if(msgid != NULLCHAR) {
  811.           sprintf(m->line,"%s\n",msgid);
  812.           strcat(*rhdr,m->line);
  813.          }
  814.          free(msgid);
  815.          free(date);
  816.     }
  817.     strcpy(m->line,subject);
  818.     return 0;
  819. }
  820.  
  821. void
  822. scanmail(m)         /* Get any new mail */
  823. struct mbx *m;
  824. {
  825.     FILE *nfile;
  826.     int ret, cnt;
  827.     char buf[256];
  828.     long diff;
  829.  
  830.     if ((diff = isnewmail(m)) == 0L)
  831.         return;
  832.     if(lockit(m))
  833.         return;
  834.     if(m->mfile == NULLFILE || diff < 0L) {
  835.         /* This is the first time scanmail is called, or the
  836.          * mail file size has decreased. In the latter case,
  837.          * any changes we did to this area will be lost, but this
  838.          * is not fatal.
  839.          */
  840.         initnotes(m);
  841.         rmlock(Mailspool,m->area);
  842.         return;
  843.     }
  844.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  845.     if ((nfile = fopen(buf,READ_TEXT)) == NULLFILE)
  846.         tprintf(Noaccess,buf);
  847.     else {
  848.         /* rewind tempfile */
  849.         fseek(m->mfile,0L,0);
  850.         cnt = m->nmsgs;
  851.         /* Reread all messages since size they may have changed
  852.          * in size after a X-Forwarded-To line was added.
  853.          */
  854.         m->nmsgs = 0;
  855.         ret = readnotes(m,nfile,1);   /* get the mail */
  856.         m->newmsgs += m->nmsgs - cnt;
  857.         m->mboxsize = ftell(nfile);
  858.         if(!stricmp(m->name,m->area))
  859.             m->mysize = m->mboxsize;
  860.         (void) fclose(nfile);
  861.         if (ret != 0)
  862.             tprintf("Error updating mail file\n");
  863.     }
  864.     rmlock(Mailspool,m->area);
  865. }
  866.  
  867. /* Check the current mailbox to see if new mail has arrived.
  868.  * Returns the difference in size.
  869.  */
  870. static long
  871. isnewmail(m)
  872. struct mbx *m;
  873. {
  874.     char buf[256];
  875.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  876.     return fsize(buf) - m->mboxsize;
  877. }
  878.  
  879. /* Check if the private mail area has changed */
  880. long
  881. isnewprivmail(m)
  882. struct mbx *m;
  883. {
  884.     long cnt;
  885.     char buf[256];
  886.     sprintf(buf,"%s/%s.txt",Mailspool,m->name);
  887.     cnt = m->mysize;
  888.     m->mysize = fsize(buf);
  889.     return m->mysize - cnt; /* != 0 not more than once */
  890. }
  891.  
  892. char *Hdrs[] = {
  893.     "Approved: ",
  894.     "From: ",
  895.     "To: ",
  896.     "Date: ",
  897.     "Message-Id: ",
  898.     "Subject: ",
  899.     "Received: ",
  900.     "Sender: ",
  901.     "Reply-To: ",
  902.     "Status: ",
  903.     "X-BBS-Msg-Type: ",
  904.     "X-Forwarded-To: ",
  905.     "Cc: ",
  906.     "Return-Receipt-To: ",
  907.     "Apparently-To: ",
  908.     "Errors-To: ",
  909.     "Organization: ",
  910.     NULLCHAR
  911. };
  912.  
  913. /* return the header type */
  914. int
  915. htype(s)
  916. char *s;
  917. {
  918.     register char *p;
  919.     register int i;
  920.  
  921.     p = s;
  922.     /* check to see if there is a ':' before and white space */
  923.     while (*p != '\0' && *p != ' ' && *p != ':')
  924.         p++;
  925.     if (*p != ':')
  926.         return NOHEADER;
  927.  
  928.     for (i = 0; Hdrs[i] != NULLCHAR; i++) {
  929.         if (strnicmp(Hdrs[i],s,strlen(Hdrs[i])) == 0)
  930.             return i;
  931.     }
  932.     return UNKNOWN;
  933. }
  934.  
  935. /* This function returns the length of a file. The proper thing would be
  936.  * to use stat(), but it fails when using DesqView together with Turbo-C
  937.  * code.
  938.  */
  939. static long
  940. fsize(name)
  941. char *name;
  942. {
  943.     long cnt;
  944.     FILE *fp;
  945.     if((fp = fopen(name,READ_TEXT)) == NULLFILE)
  946.         return -1L;
  947.     fseek(fp,0L,2);
  948.     cnt = ftell(fp);
  949.     fclose(fp);
  950.     return cnt;
  951. }
  952.  
  953. /* close the temporary mail file */
  954. static void
  955. mfclose(m)
  956. struct mbx *m;
  957. {
  958.     if(m->mfile != NULLFILE)
  959.         fclose(m->mfile);
  960.     m->mfile = NULLFILE;
  961. #ifdef SETVBUF
  962.     free(m->stdoutbuf);
  963.     m->stdoutbuf = NULLCHAR;
  964. #endif
  965. }
  966.  
  967. /* Parse a string in the "Text: <user@host>" or "Text: user@host (Text)"
  968.  * format for the address user@host.
  969.  */
  970. char *
  971. getaddress(string,cont)
  972. char *string;
  973. int cont;        /* true if string is a continued header line */
  974. {
  975.     char *cp, *ap = NULLCHAR;
  976.     int par = 0;
  977.     if((cp = getname(string)) != NULLCHAR) /* Look for <> style address */
  978.          return cp;
  979.     cp = string;
  980.     if(!cont)
  981.          if((cp = strchr(string,':')) == NULLCHAR)    /* Skip the token */
  982.           return NULLCHAR;
  983.          else
  984.           ++cp;
  985.     for(; *cp != '\0'; ++cp) {
  986.          if(par && *cp == ')') {
  987.           --par;
  988.           continue;
  989.          }
  990.          if(*cp == '(')        /* Ignore text within parenthesis */
  991.           ++par;
  992.          if(par)
  993.           continue;
  994.          if(*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ',') {
  995.           if(ap != NULLCHAR)
  996.                break;
  997.           continue;
  998.          }
  999.          if(ap == NULLCHAR)
  1000.           ap = cp;
  1001.     }
  1002.     *cp = '\0';
  1003.     return ap;
  1004. }
  1005.  
  1006. /* Print prompt and read one character, telnet version */
  1007. static int
  1008. tkeywait(prompt,flush)
  1009. char *prompt;    /* Optional prompt */
  1010. int flush;    /* Flush queued input? */
  1011. {
  1012.     int c, i, oldimode,oldomode;
  1013.  
  1014.     if(flush && socklen(Curproc->input,0) != 0)
  1015.         recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
  1016.     if(prompt == NULLCHAR)
  1017.         prompt = "Hit enter to continue"; 
  1018.     tprintf("%s%c%c%c",prompt,IAC,WILL,TN_ECHO);
  1019.     usflush(Curproc->output);
  1020.  
  1021.     /* discard the response */
  1022.  
  1023.     oldimode = sockmode(Curproc->input,SOCK_BINARY);
  1024.     oldomode = sockmode(Curproc->output,SOCK_BINARY);
  1025.  
  1026.     while((c = rrecvchar(Curproc->input)) == IAC){
  1027.         c = rrecvchar(Curproc->input);
  1028.         if(c > 250 && c < 255)
  1029.             rrecvchar(Curproc->input);
  1030.     }
  1031.  
  1032.     sockmode(Curproc->output,oldomode);
  1033.     sockmode(Curproc->input,oldimode);
  1034.  
  1035.     /* Get rid of the prompt */
  1036.     for(i=strlen(prompt);i != 0;i--)
  1037.         tputc('\b');
  1038.     for(i=strlen(prompt);i != 0;i--)
  1039.         tputc(' ');
  1040.     for(i=strlen(prompt);i != 0;i--)
  1041.         tputc('\b');
  1042.     tprintf("%c%c%c",IAC,WONT,TN_ECHO);
  1043.     usflush(Curproc->output);
  1044.     return c;
  1045. }
  1046.